package ServiceProvider;

import java.util.*;
import javax.jms.*;
import javax.naming.*;

import DataCenter.ConfigAccessor;
import DataCenter.ConfigModifier;

public class SubscriptionCenter {

	private static SubscriptionCenter instance;
	
	private ConfigAccessor configAccessor;
	private ConfigModifier configModifier;
	private HashSet<String> subscribedTopics;
	
	private SubscriptionReceiver subscriptionReceiver;
	
	private Context ctx;
	private TopicConnection topicCont;
	private TopicSession topicSession;
	private final static String topicConFac = "TopicCF";
	
	private HashMap<String, TopicSubscriber> topicSubscribers;
	
	public static synchronized SubscriptionCenter sharedInstance() {
		if (instance == null)
			instance = new SubscriptionCenter();
		return instance;
	}
	
	private SubscriptionCenter() {
		try {
			this.configAccessor = ConfigAccessor.sharedInstance();
			this.configModifier = ConfigModifier.sharedInstance();
			this.subscribedTopics = configAccessor.getSubscribedTopicNamesSet();
			
			this.subscriptionReceiver = new SubscriptionReceiver();
			
			this.ctx = new InitialContext();
			this.topicCont = createTopicContThroughJNDI();
			this.topicSession = topicCont.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
			this.topicSubscribers = createTopicSubscribers(subscribedTopics);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private TopicConnection createTopicContThroughJNDI() throws Exception{
		TopicConnection topicCon = null;
		TopicConnectionFactory tcFactory = (TopicConnectionFactory) ctx.lookup(topicConFac);
		topicCon = tcFactory.createTopicConnection();
		return topicCon;
	}
	
	private HashMap<String, TopicSubscriber> createTopicSubscribers
										(HashSet<String> subTopics) throws Exception{
		HashMap<String, TopicSubscriber> tSubscribers = new HashMap<String, TopicSubscriber>();
		
		for (String topicName : subTopics) {
			if (!topicName.isEmpty()) {
				TopicSubscriber topicSubscriber = createTopicSubscriber(topicName);
				tSubscribers.put(topicName, topicSubscriber);
			}
		}
		
		return tSubscribers;
	}
	
	public void startConnection() {
		try {
			topicCont.start();
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
	
	public void endConnection() {
		try {
			topicCont.close();
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * update the listened topic subscriber
	 */

	public void beginUpdate() {
		configModifier.beginUpdate();
	}
	
	public void endUpdate() {
		configModifier.endUpdate();
	}
	
	public void listenNewTopic(String topicName) {
		TopicSubscriber topicSubscriber = createTopicSubscriber(topicName);
		topicSubscribers.put(topicName, topicSubscriber);
		configModifier.addTheSubscribedTopic(topicName);
	}
	
	private TopicSubscriber createTopicSubscriber(String topicName) {
		try {
			Topic topic = (Topic) ctx.lookup(topicName);
			TopicSubscriber topicSubscriber = this.topicSession.createSubscriber(topic);
			topicSubscriber.setMessageListener(subscriptionReceiver);
			return topicSubscriber;
		} catch (NamingException e) {
			e.printStackTrace();
		} catch (JMSException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public void unlistenAlreadyListenedTopic(String topicName) {
		removeListenedTopicSubscriber(topicName);
		configModifier.removeTheSubscribedTopic(topicName);
	}
	
	private void removeListenedTopicSubscriber(String topicName) {
		try {
			topicSubscribers.get(topicName).close();
			topicSubscribers.remove(topicName);
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
	
}
